home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / GRAPHICS / SPHERES.ZIP / SPHERES.TXT
Encoding:
Text File  |  1996-04-26  |  15.6 KB  |  690 lines

  1.  
  2.  
  3.  
  4.  
  5. Subject: Texturing, Bumpmapping of Spheres in Realtime
  6.  
  7. Date: 23 Apr 1995 20:27:07 GMT
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16. FAST TEXTURING OF SPHERES 
  17.  
  18.  
  19. Two weeks ago I posted an article that outlined a method for the
  20.  
  21. fast texture mapping of parallel projected spheres. In this article
  22.  
  23. I asked if this method is something new. I got two letters from
  24.  
  25. people who had developed their own algorithms for the fast texturing
  26.  
  27. of spheres, though both didn't publish them. There was no letter that
  28.  
  29. said that this algorithm has been published somewhere.
  30.  
  31.  
  32. In this article I will try to give a better explanation of the
  33.  
  34. method I used, and I will describe some extensions, like
  35.  
  36. diffuse shading, bump mapping and specular shading of spheres in
  37.  
  38. realtime.
  39.  
  40.  
  41. If you think that drawing spheres is a stupid thing to do,
  42.  
  43. read this article even though. Some of the techniques described can
  44.  
  45. be used in other algorithms as well.
  46.  
  47.  
  48. All algorithms are scanline-orientated and require only
  49.  
  50. table-lookups, additions and some logical operations in the
  51.  
  52. interior loops. I implemented the algorithms in this article.
  53.  
  54.  
  55. The basic idea of all algorithms is to store both points on the
  56.  
  57. sphere's surface and vectors in spherical coordinates, and to
  58.  
  59. convert this coordinates always into that spherical coordinate
  60.  
  61. system (SCS), in which the thing that you want to to is
  62.  
  63. particulary easy.
  64.  
  65. The conversion between different SCS can be done fast using
  66.  
  67. a lookup-table.
  68.  
  69.  
  70. SPHERICAL COORDINATES (SC)
  71.  
  72.  
  73. Sperical coordinates appear in a lot of math textbooks,
  74.  
  75. though I will give a short description, since SC are essential
  76.  
  77. for the algorithms below.
  78.  
  79.  
  80. To describe a point in space using SC, you need two angles,
  81.  
  82. alpha e [0..2Pi[ and beta e [-Pi/2..Pi/2[, and the distance r
  83.  
  84. of the point to the origin. Since I use only points on spheres
  85.  
  86. and normalized vectors, r is always constant, and I don't have
  87.  
  88. to regard it any further.
  89.  
  90. A exemplary SCS is that of the earth, with the longitude as the
  91.  
  92. first angle alpha, and the latitude as the second angle beta.
  93.  
  94. Every SCS has a special axis, the polar axis. The polar axis is
  95.  
  96. the line were beta = -Pi/2 or beta = Pi/2, e.g. the polar axis
  97.  
  98. of the earth's SCS just connects the two poles of the earth.
  99.  
  100. To convert SC given in a SCS with the y-axis as polar-axis into
  101.  
  102. kartesian coordinates, take the following formula:
  103.  
  104. x = r*cos(alpha)*cos(beta)
  105.  
  106. y = r*sin(beta)
  107.  
  108. z = r*sin(alpha)*cos(beta)
  109.  
  110.  
  111. For my purposes, the most important property of SCS's is, that
  112.  
  113. it is very easy to rotate a point given in SC around the polar
  114.  
  115. axis of the SCS. You just have to add the desired angle to the
  116.  
  117. alpha-coordinate of the point. Nevertheless, it is very difficult
  118.  
  119. to rotate a point in SC around any other axis.
  120.  
  121. But if you want to move a texture or anything else into an arbitrary
  122.  
  123. position, you have to rotate it at least around 3 axis. Why this is so
  124.  
  125. is discussed in many physic textbooks (any rigid body with a single
  126.  
  127. fixed point has three degrees of freedom).
  128.  
  129.  
  130. To solve this problem, I convert the SC from the first SCS into a
  131.  
  132. second SCS with a polar axis identical to the second axis of rotation.
  133.  
  134. In physics the second axis of rotation is choosen perpendicular to the
  135.  
  136. first. I will do the same.
  137.  
  138.  
  139. Our problem at the moment is the conversion between the two SCS's:
  140.  
  141. We have a fixed point in a first SCS, and want to compute the SC of
  142.  
  143. that point in a second SCS.
  144.  
  145. I will derive the formula that does this for a first SCS with the
  146.  
  147. y-axis as polar axis and a second SCS with the z-axis as polar axis: 
  148.  
  149.  
  150. First, I convert the point from the first SCS into kartesian
  151.  
  152. coordinates:
  153.  
  154. x = cos(alpha1)*cos(beta1)
  155.  
  156. y = sin(beta1)
  157.  
  158. z = sin(alpha1)*cos(beta1)
  159.  
  160. Then, I convert the point from kartesian coordinates into the
  161.  
  162. second SCS:
  163.  
  164. beta2 = arcsin(z)
  165.  
  166. w = x/cos(beta2)
  167.  
  168. alpha2 = arccos(w)
  169.  
  170. if (y/cos(beta2) < 0) alpha2 = Pi*2 - alpha2
  171.  
  172. This is just the inverse of the mapping above, with y and z exchanged.
  173.  
  174.  
  175. To compute this formula during rendering, I store the mapping in
  176.  
  177. a large 2D-lookuptable. How this is done is described below.
  178.  
  179.  
  180. Now I can rotate the point in this second SCS. But I still have
  181.  
  182. to rotate the point around a third axis. To do this, I go in
  183.  
  184. a third SCS, that's polar axis is perpendicular to the second axis.
  185.  
  186. I can use the same mapping for the conversion from the second
  187.  
  188. SCS to the third SCS as I used for the conversion from the first to
  189.  
  190. the second SCS. Note, that the third SCS is different from the first!
  191.  
  192. For illustrations, what happens to a 3D-object when it is rotated
  193.  
  194. in this way, see a physics textbook that deals with 'rigid bodies' or
  195.  
  196. 'euler angles'.
  197.  
  198.  
  199. DOING IT FAST
  200.  
  201.  
  202. To do this stuff fast during rendering, you first have to convert the
  203.  
  204. spherical coordinates into unsigned integers.
  205.  
  206. I do this in a straighforward way:
  207.  
  208. alpha_int = alpha/(2*pi)*S
  209.  
  210. beta_int = (beta+Pi/2)/Pi*S
  211.  
  212. where 0..S is the range of the integer-SC
  213.  
  214. (0 <= alpha_int < S, 0 <= beta_int < S)
  215.  
  216. I will store the two SC in a single integer, using the first
  217.  
  218. n bits for alpha_int, and the second n bits for beta_int (n = log2(S)):
  219.  
  220. alpha_beta_int = alpha + beta*S.
  221.  
  222. If you choose S=256, 16 bit are sufficent for storing a SC.
  223.  
  224.  
  225. The lookuptable for the converting between the two SCS's in then a
  226.  
  227. array of short int's of the size S*S.
  228.  
  229.  
  230. Here's pseudo-code, how to compute it:
  231.  
  232. for alpha_int1 = 0 to S-1
  233.  
  234.  for beta_int1 = 0 to S-1
  235.  
  236.   (alpha1,beta1) = convert_to_double(alpha_int1,beta_int1)
  237.  
  238.   (x,y,z) = convert_to_kartesian(alpha1,beta1)     (1) 
  239.  
  240.   (alpha2,beta2) = convert_to_spherical(x,y,z)     (2) 
  241.  
  242.   (alpha_int2,beta_int2) = convert_to_int(alpha2,beta2)
  243.  
  244.   LOOKUPTABLE[alpha_int1 + beta_int1*S] = alpha_int2 + beta_int2*S
  245.  
  246.  next
  247.  
  248. next
  249.  
  250.  
  251. The function in line (1) uses a SCS with the x-axis as polar axis,
  252.  
  253. while the function in line (2) uses a SCS with z-axis as polar axis.
  254.  
  255.  
  256. TEXTURING
  257.  
  258.  
  259. The parallel projected textured sphere is drawn scanline by scanline
  260.  
  261. and pixel by pixel.
  262.  
  263. In every scanline I first have to compute the width of the sphere
  264.  
  265. in that scanline (scanconvert the contour of the projected sphere).
  266.  
  267. Then, compute the color of every pixel in this horizonal span that
  268.  
  269. is covered by the sphere.
  270.  
  271. I will use a kartesian koordinate system with the z-axis
  272.  
  273. perpendicular to the screen, and that has a origin that lies in the
  274.  
  275. center of the sphere.
  276.  
  277.  
  278. At first, I have to map each pixel (x,y) onto the sphere, and
  279.  
  280. convert this point on the sphere into the SC (alpha,beta).
  281.  
  282. For this purpose, I use a initial SCS, so that this mapping is
  283.  
  284. particulary easy and I can do both, the mapping onto the sphere and
  285.  
  286. the conversion into SC, in a single step.
  287.  
  288. The SCS that fulfills this requirements has a polar axis that is
  289.  
  290. identical to the y-axis. (again, if you take the SCS of the earth,
  291.  
  292. you would look towards the equator).
  293.  
  294. The formula to do the mapping with a sphere of radius r is :
  295.  
  296. beta1 = asin(y/r)
  297.  
  298. alpha1 = acos(x/sqrt(r^2-y^2))
  299.  
  300. (2*sqrt(r^2-y^2) is the width of the sphere in scanline y)
  301.  
  302. This formula is computed during rendering using lookuptables.
  303.  
  304.  
  305. Now I can rotate this point around the three axis, as described above.
  306.  
  307. The texture is stored also in SC so that the only thing remaining
  308.  
  309. is to look up the color. (the texture is an array of color-values
  310.  
  311. of the size S*S).
  312.  
  313.  
  314. Here's the algorithm in pseudo-code:
  315.  
  316.  
  317. for x = -r to r
  318.  
  319.  for y = -sqrt(r*r-y*y) to sqrt(r*r-y*y)
  320.  
  321.    beta1 = ARCSIN_TABLE[x*S/(r*2)+S/2]
  322.  
  323.    alpha1 = ARCCOS_TABLE[y*S/(2*sqrt(r*r-y*y))+S/2] + phi
  324.  
  325.    alpha_beta_2 = LOOKUPTABLE[alpha1 + beta1*S] + theta
  326.  
  327.    alpha_beta_3 = LOOKUPTABLE[alpha_beta_2] + psi
  328.  
  329.    putpixel(x,y,TEXTURE[alpha_beta_3])
  330.  
  331.  next
  332.  
  333. next
  334.  
  335.  
  336. where
  337.  
  338.  ARCSIN_TABLE[i] = arcsin(i*2/S-1)*S/PI+S/2 , (i=0..S)
  339.  
  340.  ARCCOS_TABLE[i] = arccos(i*2/S-1)*S/(PI*2) , (i=0..S)
  341.  
  342.  phi, theta and psi are the angles used in the three rotations
  343.  
  344.   
  345.  
  346. In this pseudo-code I ignored the problem, that e.g. alpha_beta_2
  347.  
  348. may become greater than S*S, but the 2D-lookuptable has only the
  349.  
  350. size S*S.
  351.  
  352. To solve this problem, you can either use masking-operations, or
  353.  
  354. use a 2D-lookuptable and a texture of the size S*S+S.
  355.  
  356. (LOOKUPTABLE[S*S+i] = LOOKUPTABLE[i] , i = 0..S)
  357.  
  358. You may have noticed, that the programm contains still squareroots
  359.  
  360. and multiplications/divisions. It isn't too hard to remove these
  361.  
  362. using another lookuptable and fixed-point forward-differencing.
  363.  
  364.  
  365. DIFFUSE SHADING
  366.  
  367.  
  368. The intensity-distribution on a sphere that is lit by a lightsource
  369.  
  370. is also a texture. So, you can use the techniques in the chapter
  371.  
  372. above for diffuse shading of spheres. The only thing you have to
  373.  
  374. adapt is the preprocessing.
  375.  
  376. Here's a pseudocode to compute a intensity-texture :
  377.  
  378.  
  379. for alpha = 0 to S
  380.  
  381.  for beta = 0 to S
  382.  
  383.   (x,y,z) = convertSCtokartesian(alpha,beta)
  384.  
  385.   INTENSITY_TEXTURE[alpha+beta*S] = shade_sphere(x,y,z)
  386.  
  387.  next
  388.  
  389. next
  390.  
  391.  
  392. This method can be used to draw spheres that are lit by more than
  393.  
  394. one lightsource.
  395.  
  396.  
  397. BUMP-MAPPING
  398.  
  399.  
  400. A bump-map is similiar to a texture, with the difference that it does
  401.  
  402. not map color-values to points on the sphere, but surface-normals.
  403.  
  404. If you use bump-maps, you use the normal you found in the bump-map to
  405.  
  406. shade a given point on the sphere, and not the true normal of the
  407.  
  408. sphere at this point.
  409.  
  410. I store surface-normals in SC, too. So, I use a array of short int's
  411.  
  412. of the size S*S to store the bump-map.
  413.  
  414. Once I got the surface-normal I have to compute the intensity.
  415.  
  416. If the incident light is parallel, this can be done using
  417.  
  418. intensity-textures, too. Note, that a intensity-texture then can be
  419.  
  420. seen as a mapping from surface-normals to intensities.
  421.  
  422. You can rotate surface-normals in the same way as you rotated points
  423.  
  424. on the sphere.
  425.  
  426.  
  427. a pseudo-code for bump-mapping follows :
  428.  
  429.  
  430. for each pixel (x,y)
  431.  
  432.  (alpha1,beta1) = converttoSC(x,y)
  433.  
  434.  alpha1 = alpha1 + phi1
  435.  
  436.  alpha_beta2 = LOOKUPTABLE[alpha1+beta1*S]+theta1
  437.  
  438.  alpha_beta3 = LOOKUPTABLE[alpha_beta2]+psi1
  439.  
  440.  normal1 = BUMPMAP[alpha_beta3]+phi2
  441.  
  442.  normal2 = LOOKUPTABLE[normal1]+theta2
  443.  
  444.  normal3 = LOOKUPTABLE[noraml2]+psi2
  445.  
  446.  putpixel(x,y,INTENSITY_TEXTURE[normal3])
  447.  
  448. next
  449.  
  450.  
  451. Note, that this algorithm involves 6 rotations:
  452.  
  453. first, I rotate the bump-map, using 3 rotations, then
  454.  
  455. I rotate the light-vector/surface-normal, using again 3 rotations.
  456.  
  457. The first few lines in this pseudo-code would be identical to
  458.  
  459. the code for the texture-mapping, so I abbreviated them.
  460.  
  461.  
  462. SPECULAR SHADING
  463.  
  464.  
  465. Specular shading is harder to do than diffuse shading.
  466.  
  467. For specular shading, I have to compute the direction of the ray
  468.  
  469. coming from the eye of the viewer, after it has been reflected on the
  470.  
  471. spheres surface. To do this, I go into that SCS, where the computing
  472.  
  473. of the reflected ray is particulary easy. This is the
  474.  
  475. SCS with the polar axis parallel to the direction of view.
  476.  
  477. In this SCS, the direction of the reflected ray can be computed by
  478.  
  479. multiplying the (integer-) beta-coordinate of a given
  480.  
  481. point by 2 (draw it!!!).
  482.  
  483. Again, all incident light should be parallel, so that the intensity
  484.  
  485. of the point depends only on the direction of the reflected ray.
  486.  
  487. The actual computation of the intensity is done using a
  488.  
  489. intensity-texture, that contains a intensity-value for every direction
  490.  
  491. of the ray.
  492.  
  493.  
  494. here's the pseudo-code for specular shading:
  495.  
  496.  
  497. for each pixel (x,y)
  498.  
  499.   (alpha1,beta1) = converttoSC(x,y)
  500.  
  501.   alpha_beta2 = LOOKUPTABLE[alpha1+beta1*S]           (1)
  502.  
  503.   alpha2 = alpha_beta2 and (S-1)                      (2)
  504.  
  505.   beta2 =  alpha_beta2/S
  506.  
  507.   beta2 = beta2*2
  508.  
  509.   alpha2 = alpha2 + phi
  510.  
  511.   alpha_beta3 = LOOKUPTABLE[alpha2+beta2*S] + theta
  512.  
  513.   alpha_beta4 = LOOKUPTABLE[alpha_beta3] + psi
  514.  
  515.   putpixel(x,y,INTENSITY_TEXURE[alpha_beta4]
  516.  
  517. next
  518.  
  519.  
  520. The 'and' in line (2) is a bitwise and, that is used
  521.  
  522. to extract alpha2 out of alpha_beta2.
  523.  
  524. In line (1), LOOKUPTABLE[] is used to convert SC from
  525.  
  526. a SCS with the y-axis as polar axis to a SCS with the z-axis as
  527.  
  528. polar axis.
  529.  
  530. This has to be regared while initializing the 2d-lookuptable.
  531.  
  532.  
  533. To compute the intensity-texture during preprocessing, use
  534.  
  535. the formula for specular shading that can be found e.g. in
  536.  
  537. Foley/VanDam:
  538.  
  539. I = I0*cos(delta)^e
  540.  
  541. 'delta' is the angle between the reflected ray and the incident light.
  542.  
  543. 'e' is a constant (e.g. 12).
  544.  
  545. Again, you can use this method to texture spheres that are lit by
  546.  
  547. more than one lightsource. 
  548.  
  549.  
  550. Note, that this algorithm does not test, if the light does really
  551.  
  552. reach a point on the sphere. This is a serious flaw of this
  553.  
  554. algorithm, which has the effect that a lightsource behind
  555.  
  556. the sphere causes a lit circle at the margin of the sphere.
  557.  
  558. At least if you use only one lightsource, there should be
  559.  
  560. a efficent way to do a appropriate test.
  561.  
  562.  
  563.  
  564. THINGS I DIDN'T DO
  565.  
  566.  
  567. The things in this chapter were neither tested nor implemented.
  568.  
  569.  
  570. If a sphere is illuminated by a single lightsource, you can
  571.  
  572. use the symetry of the intensity-distribution to
  573.  
  574. reduce either the number of table-lookups or the size of the
  575.  
  576. intensity-texture (a one-dimensional texture is then sufficent).
  577.  
  578.  
  579. The use of spherical coordinates can be fruitful for other realtime-
  580.  
  581. graphic-algorithms as well. In the chapter 'Specular Shading'
  582.  
  583. I computed the direction of a reflected ray without multiplications.
  584.  
  585. It should be possible to do other calculations with normalized vectors
  586.  
  587. in spherical coordinates and without multiplications as well,
  588.  
  589. e.g. the computing of normalized vector-products or dot-products.
  590.  
  591. Remember the basic idea of the algorithms in this article :
  592.  
  593. To do something, go into that SCS, in which the thing you want to
  594.  
  595. do is particulary easy.
  596.  
  597.  
  598. The method I used to bump-map spheres can be used to bump-map
  599.  
  600. polygons as well.
  601.  
  602.  
  603. If you want to texture planets in a flight-simulator, the
  604.  
  605. rotation that has to be applied to the planets before drawing is given
  606.  
  607. in the form of an orthogonal matrix. But the texturing-algorithm
  608.  
  609. uses 3 angles to describe such a rotation. So, you have to
  610.  
  611. convert the orthogonal matrix into the three angles.
  612.  
  613.  
  614.  
  615. MISCELLANEOUS
  616.  
  617.  
  618. Using assembler language the programs above can be optimized highly.
  619.  
  620. I achieved 17 fps at texturing a sphere of 100 pixel diameter
  621.  
  622. on a 286/12Mhz.
  623.  
  624.  
  625. Of course, the algorithms described can be used free of royalities.
  626.  
  627. This article may be redistributed.
  628.  
  629.  
  630. Here's a short summary of some of the mail I got about the first
  631.  
  632. article:
  633.  
  634. Joe Lee and Mike Currington have developed their own algorithms for
  635.  
  636. the fast texture mapping of spheres with diffuse shading.
  637.  
  638. Diana Gruber send me some suggestions for improving the
  639.  
  640. C++-source. My code wasn't really well optimized.
  641.  
  642. Steve Metke suggested the extension of this algorithm to
  643.  
  644. ellipsoids. I agree, that this should be possible, though it
  645.  
  646. will not be easy.
  647.  
  648.  
  649. Here's a list of books that might help you to implement or
  650.  
  651. understand the algorithms:
  652.  
  653. * Foley/vanDam (shading, introduction to 3D-graphics)
  654.  
  655. * PCGPE, Mark Feldmann et al.
  656.  
  657.   (fixed-point math, assembler coding, shading,
  658.  
  659.    introduction to 3D-graphics, planar texture mapping)
  660.  
  661.   (the PCGPE can be found on a lot of ftp-servers)
  662.  
  663. * Classical Mechanics, H.Goldstein, (euler angles)
  664.  
  665.  
  666. I will post a source for Watcom/Turbo C++ that does the things
  667.  
  668. above to comp.sys.ibm.pc.demos.
  669.  
  670.  
  671. Please, don't ask for executables. Maybe I make a demo about
  672.  
  673. spheres in the next few months and upload it to a ftp-server.
  674.  
  675.  
  676. I am a student of computer science at the university in
  677.  
  678. Erlangen/Germany.
  679.  
  680.  
  681. Thanks for reading this, 
  682.  
  683.  
  684. Hans Kopp,  4.22.1995
  685.  
  686.   
  687.  
  688.  
  689.  
  690.